import { _decorator, Animation, AudioClip, clamp, Collider2D, Color, color, Component, ERaycast2DType, ERigidBody2DType, EventTouch, IPhysics2DContact, js, Node, PhysicsSystem2D, Prefab, randomRange, RaycastResult2D, Sprite, SpriteFrame, toRadian, tween, Tween, UITransform, v2, v3, Vec2, Vec3 } from 'cc';
import { EasingType } from '../../Scripts/Framework/Utils/TweenUtil';
import { GameData, WearType } from './GameData';
import { Subject, TweenTag } from './Subject';
import { MigaManager } from './MigaManager';
import { PoolManager } from '../../Scripts/Framework/Managers/PoolManager';
import { Item } from './Item';
import { LayerFloor } from './GameItems/LayerFloor';
import { PolygonPlane } from './GameItems/PolygonPlane';
import { AudioManager } from '../../Scripts/Framework/Managers/AudioManager';
const { ccclass, property } = _decorator;

@ccclass('Person')
export class Person extends Subject {

    @property
    defaultId = -1;

    @property(LayerFloor)
    layerFloor: LayerFloor;

    @property([Node])
    hands: Node[] = [];

    @property([Node])
    handContacts: Node[] = [];

    @property([Sprite])
    skins: Sprite[] = [];

    @property([Sprite])
    wears: Sprite[] = [];

    @property([AudioClip])
    clips: AudioClip[] = [];

    leftArm: Node;
    rightArm: Node;
    leftLeg: Node;
    rightLeg: Node;
    eyeClose: Node;
    head: Node;
    mouth: Node;
    eye: Node;
    eyebrow: Node;
    expressions: Node;
    effects: Node;

    id: number;
    eatNum = 0;

    canSit = false;
    isExpress = false;
    isEatDisgust = false;

    state: PersonState = PersonState.Idle;

    expState: ExpressState = ExpressState.None;

    mouthState: MouthState = MouthState.None;

    standState: StandState = StandState.None;

    handStates: HandState[] = [HandState.None, HandState.None];

    handTarget: Node[] = [null, null];

    update(deltaTime: number) {
        this.CheckMove();
        this.CheckSit();
    }

    static Init(parent: Node): Person {
        let node: Node = PoolManager.GetNodeByPrefab(GameData.prefabsBundle.get("Person", Prefab), parent);
        node.setPosition(Vec3.ZERO);
        return node.getComponent(Person);
    }

    Init() {
        super.Init();
        this.leftArm = this.node.children[1];
        this.rightArm = this.node.children[2];
        this.leftLeg = this.node.children[3];
        this.rightLeg = this.node.children[4];
        this.eyeClose = this.node.children[9].children[0];
        this.head = this.node.children[12];
        this.mouth = this.node.children[20];
        this.eyebrow = this.node.children[15];
        this.eye = this.node.children[16];
        this.expressions = this.node.children[19];
        this.effects = this.node.children[23];
        // tween(this.eyeClose).tag(TweenTag.Face)
        //     .delay(randomRange(5, 10)).set({ active: true })
        //     .delay(randomRange(0.1, 0.5)).set({ active: false })
        //     .union().repeatForever().start();
    }

    DataInit(data: any) {
        this.id = data.id;
        this.ColorInit(data.color);
        this.ClothesInit(data.data);
        this.HandInit(data.hands);
    }

    ColorInit(data: any) {
        let c: Color;
        if (data instanceof Color) {
            c = data;
            let personData = GameData.Instance.getRecordData("PersonData");
            personData[this.id].color = [c.r, c.g, c.b];
            GameData.Instance.setRecordData("PersonData", personData);
        }
        else c = color(data[0], data[1], data[2], 255);
        for (let i = 0; i < this.skins.length; i++) {
            const element = this.skins[i];
            element.color = c;
        }
    }

    ClothesInit(data) {
        let nums: [string, unknown][] = [...(Object.entries(data))];
        let urls: string[] = [];
        for (let i = 0; i < nums.length; i++) {
            const element = nums[i];
            if (element[0].includes("L") || element[0].includes("R")) urls.push(element[0].slice(1) + "/" + element[1]);
            else if (element[0] == "hair") {
                urls.push("F" + element[0] + "/" + element[1]);
                urls.push("B" + element[0] + "/" + element[1]);
            }
            else urls.push(element[0] + "/" + element[1]);
        }
        urls.push("sleeve/" + nums[2][1], "leg/" + nums[3][1]);
        for (let i = 0; i < urls.length; i++) {
            let element: string = urls[i];
            if ((element.charAt(element.length - 2) + element.charAt(element.length - 1)) != "-1") this.wears[i].spriteFrame = GameData.clothesBundle.get(element + "/spriteFrame", SpriteFrame);
            else this.wears[i].spriteFrame = null;
        }
        this.wears[19].spriteFrame = this.wears[16].spriteFrame;
        this.wears[20].spriteFrame = this.wears[17].spriteFrame;
        this.wears[21].spriteFrame = this.wears[18].spriteFrame;
    }

    HandInit(data: string[]) {
        return;
        for (let i = 0; i < data.length; i++) {
            const element = data[i];
            if (element == "") continue;
            let name = "Item";
            if (element.includes("Clothes")) name = "Wear";
            let node: Node = PoolManager.GetNodeByPrefab(GameData.prefabsBundle.get(name, Prefab), this.handContacts[i]);
            node.setPosition(Vec3.ZERO);
            this.handTarget[i] = node;
            this.hands[i].angle = i == 0 ? -50 : 50;
            let item = node.getComponent(Item);
            item.handPerson = this;
            item.HandInit(element);
        }
    }

    CheckMove() {
        if (this.rig.gravityScale == 0) {
            if (this.lastPos.x == this.node.getPosition().x) this.PlayAni(PersonState.Touch);
            else if (this.lastPos.x < this.node.getPosition().x) this.PlayAni(PersonState.TouchRight);
            else if (this.lastPos.x > this.node.getPosition().x) this.PlayAni(PersonState.TouchLeft);
        }
        this.lastPos = this.node.getPosition();
    }

    CheckSit() {
        if (!this.isTouch) return;
        if (this.sitTarget) {
            let uitr = this.sitTarget.getComponent(UITransform);
            let pos = this.node.getWorldPosition().add3f(0, 100, 0);
            if (uitr.getBoundingBoxToWorld().contains(v2(pos.x, pos.y))) {
                this.canSit = true;
                Tween.stopAllByTag(TweenTag.Leg, this.leftLeg);
                Tween.stopAllByTag(TweenTag.Leg, this.rightLeg);
                this.leftLeg.angle = -30;
                this.rightLeg.angle = 30;
            }
            else {
                this.canSit = false;
                this.leftLeg.angle = 0;
                this.rightLeg.angle = 0;
            }
        }
        else if (this.canSit) {
            this.canSit = false;
            this.leftLeg.angle = 0;
            this.rightLeg.angle = 0;
        }
    }

    TouchStart(event: EventTouch): void {
        if (MigaManager.Instance.tutorial.active) {
            if (GameData.tutorial == 5 && this.id == 6) MigaManager.Instance.NextTutorial();
            else if (!(GameData.tutorial == 1 && this.id == 0)) return;
        }
        super.TouchStart(event);
        MigaManager.Instance.lastPerson = this;
        this.layerFloor = null;
        this.Stand(0);
        if (this.rig.type = ERigidBody2DType.Animated) {
            let temp = PhysicsSystem2D.instance.physicsWorld["_animatedBodies"]
            js.array.remove(temp, this.rig.impl);
        }
        this.rig.type = ERigidBody2DType.Dynamic;
        this.rig.enabledContactListener = true;
        this.collider.enabled = true;
    }

    TouchEnd(event: EventTouch) {
        if (!this.isTouch) return;
        if (MigaManager.Instance.tutorial.active) {
            if (GameData.tutorial != 1 && GameData.tutorial != 5) return;
        }
        MigaManager.Instance.edgePoint = null;
        let gameWidth = MigaManager.Instance.game.children[0].getComponent(UITransform).width;
        let curPos = this.node.getPosition();
        curPos.x = clamp(curPos.x, -gameWidth / 2 + this.uiTransform.width / 2, gameWidth / 2 - this.uiTransform.width / 2);
        this.node.setPosition(curPos);
        let pos = event.getUILocation();
        if (MigaManager.Instance.charecterPanel.getComponent(UITransform).getBoundingBoxToWorld().contains(pos) && MigaManager.Instance.closeChara.active) {
            MigaManager.Instance.RecyclePerson(this.id);
            PoolManager.PutNode(this.node);
            return;
        }
        if (MigaManager.Instance.tutorial.active && (GameData.tutorial == 1 && this.id == 0)) MigaManager.Instance.NextTutorial();
        this.PlayAni(PersonState.TouchDown);
        Tween.stopAllByTag(TweenTag.Touch, this.node);
        tween(this.node).tag(TweenTag.Touch)
            .to(0.1, { scale: Vec3.ONE })
            .start();
        // this.rig.type = ERigidBody2DType.Dynamic;
        this.touchUpPos = this.node.getPosition();
        this.isTouch = false;
        if (this.canSit) {
            // this.rig.type = ERigidBody2DType.Animated;
            // this.rig.enabledContactListener = false;
            // this.collider.enabled = false;
            this.node.setParent(this.sitTarget, true);
            let otherWidth = this.sitTarget.getComponent(UITransform).width;
            let delta = this.sitTarget.getWorldPosition().x - this.node.getWorldPosition().x;
            let pos = v3(this.node.getWorldPosition().x, this.sitTarget.getWorldPosition().y - 100);
            if (otherWidth < this.uiTransform.width) pos.x = this.sitTarget.getWorldPosition().x;
            else if (delta > otherWidth / 2 - this.width / 2) pos.x = this.sitTarget.getWorldPosition().x - otherWidth / 2 + this.width / 2;
            else if (delta < this.width / 2 - otherWidth / 2) pos.x = this.sitTarget.getWorldPosition().x + otherWidth / 2 - this.width / 2;
            Tween.stopAllByTag(TweenTag.FallCollid, this.node);
            tween(this.node).tag(TweenTag.FallCollid)
                .to(0.2, { worldPosition: pos })
                .start();
        }
        else {
            this.rig.gravityScale = 8;
            let colliders = this.getComponentsInChildren(Collider2D);
            for (let i = 0; i < colliders.length; i++) {
                const element = colliders[i];
                if (element.tag == 1) element.enabled = false;
            }
            let pos2 = v2();
            Vec2.subtract(pos2, pos, v2(0, 10000));
            const results = PhysicsSystem2D.instance.raycast(pos, pos2, ERaycast2DType.All);
            this.rayTarget = null;
            let result: RaycastResult2D;
            if (results.length > 0) {
                let arr = [...results];
                arr.sort((a, b) => { return Vec2.distance(a.point, pos) - Vec2.distance(b.point, pos) });
                for (let i = 0; i < arr.length; i++) {
                    const element = arr[i];
                    if (element.collider.group == 1 << 2 || element.collider.group == 1 << 8 || element.collider.group == 1 << 10) {
                        result = element;
                        break;
                    }
                }
            }
            if (result) this.rayTarget = result.collider.node;
        }
    }

    PlayAni(newState: PersonState) {
        if (this.state != newState) {
            this.state = newState;
            if (this.handStates[0] == HandState.None) Tween.stopAllByTag(TweenTag.LeftArm, this.leftArm);
            if (this.handStates[1] == HandState.None) Tween.stopAllByTag(TweenTag.RightArm, this.rightArm);
            Tween.stopAllByTag(TweenTag.Leg, this.leftLeg);
            Tween.stopAllByTag(TweenTag.Leg, this.rightLeg);
            switch (this.state) {
                case PersonState.Idle:
                case PersonState.Touch:
                    if (!this.handTarget[0]) tween(this.leftArm).tag(TweenTag.LeftArm).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    if (!this.handTarget[1]) tween(this.rightArm).tag(TweenTag.RightArm).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    if (this.canSit) break;
                    tween(this.leftLeg).tag(TweenTag.Leg).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    tween(this.rightLeg).tag(TweenTag.Leg).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    break;
                case PersonState.TouchLeft:
                    if (!this.handTarget[0]) tween(this.leftArm).tag(TweenTag.LeftArm).to(0.5, { angle: 30 }, { easing: EasingType.sineOut }).start();
                    if (!this.handTarget[1]) tween(this.rightArm).tag(TweenTag.RightArm).to(0.5, { angle: 30 }, { easing: EasingType.sineOut }).start();
                    if (this.canSit) break;
                    tween(this.leftLeg).tag(TweenTag.Leg).to(0.5, { angle: 30 }, { easing: EasingType.sineOut }).start();
                    tween(this.rightLeg).tag(TweenTag.Leg).to(0.5, { angle: 30 }, { easing: EasingType.sineOut }).start();
                    break;
                case PersonState.TouchRight:
                    if (!this.handTarget[0]) tween(this.leftArm).tag(TweenTag.LeftArm).to(0.5, { angle: -30 }, { easing: EasingType.sineOut }).start();
                    if (!this.handTarget[1]) tween(this.rightArm).tag(TweenTag.RightArm).to(0.5, { angle: -30 }, { easing: EasingType.sineOut }).start();
                    if (this.canSit) break;
                    tween(this.leftLeg).tag(TweenTag.Leg).to(0.5, { angle: -30 }, { easing: EasingType.sineOut }).start();
                    tween(this.rightLeg).tag(TweenTag.Leg).to(0.5, { angle: -30 }, { easing: EasingType.sineOut }).start();
                    break;
                case PersonState.TouchUp:
                    if (!this.handTarget[0]) tween(this.leftArm).tag(TweenTag.LeftArm).to(0.5, { angle: 30 }, { easing: EasingType.sineOut }).start();
                    if (!this.handTarget[1]) tween(this.rightArm).tag(TweenTag.RightArm).to(0.5, { angle: -30 }, { easing: EasingType.sineOut }).start();
                    if (this.canSit) break;
                    tween(this.leftLeg).tag(TweenTag.Leg).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    tween(this.rightLeg).tag(TweenTag.Leg).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    break;
                case PersonState.TouchDown:
                    if (!this.handTarget[0]) tween(this.leftArm).tag(TweenTag.LeftArm).to(0.5, { angle: -30 }, { easing: EasingType.sineOut }).start();
                    if (!this.handTarget[1]) tween(this.rightArm).tag(TweenTag.RightArm).to(0.5, { angle: 30 }, { easing: EasingType.sineOut }).start();
                    if (this.canSit) break;
                    tween(this.leftLeg).tag(TweenTag.Leg).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    tween(this.rightLeg).tag(TweenTag.Leg).to(0.5, { angle: 0 }, { easing: EasingType.sineOut }).start();
                    break;
            }
        }
    }

    Wear(target: any) {
        let personData = GameData.Instance.getRecordData("PersonData");
        let targetId = target.id;
        switch (target.wearType) {
            case 0:
                target.id = personData[this.id].data.headwear;
                personData[this.id].data.headwear = targetId;
                break;
            case 1:
                target.id = personData[this.id].data.up;
                personData[this.id].data.up = targetId;
                break;
            case 2:
                target.id = personData[this.id].data.bottom;
                personData[this.id].data.bottom = targetId;
                break;
            case 3:
                target.id = personData[this.id].data.belt;
                personData[this.id].data.belt = targetId;
                break;
            case 4:
                target.id = personData[this.id].data.cloak;
                personData[this.id].data.cloak = targetId;
                break;
            case 5:
            case 6:
                if (target.handTarget == this.handContacts[0]) {
                    target.wearType = 5;
                    target.id = personData[this.id].data.Lhandwear;
                    personData[this.id].data.Lhandwear = targetId;
                    Tween.stopAllByTag(TweenTag.LeftArm, this.hands[0]);
                    tween(this.hands[0]).tag(TweenTag.LeftArm)
                        .to(0.2, { angle: 0 })
                        .start();
                }
                else {
                    target.wearType = 6;
                    target.id = personData[this.id].data.Rhandwear;
                    personData[this.id].data.Rhandwear = targetId;
                    Tween.stopAllByTag(TweenTag.RightArm, this.hands[1]);
                    tween(this.hands[0]).tag(TweenTag.RightArm)
                        .to(0.2, { angle: 0 })
                        .start();
                }
                break;
            case 7:
                target.id = personData[this.id].data.necklace;
                personData[this.id].data.necklace = targetId;
                break;
            case 8:
                target.id = personData[this.id].data.scarf;
                personData[this.id].data.scarf = targetId;
                break;
            case 9:
                target.id = personData[this.id].data.shoe;
                personData[this.id].data.shoe = targetId;
                break;
        }
        GameData.Instance.setRecordData("PersonData", personData);
        this.ClothesInit(personData[this.id].data);
        target.Init();
        AudioManager.Instance.PlaySFX(this.clips[0]);
    }

    Hand(target: any) {
        let num = this.handContacts.indexOf(target.handTarget);
        if (this.handTarget[num]) return;
        let personData = GameData.Instance.getRecordData("PersonData");
        let wearType = target.wearType;
        if (wearType != undefined) {
            let targetId = target.id;
            let url = "Clothes/" + WearType[target.wearType] + "/" + targetId + "/spriteFrame";
            personData[this.id].hands[num] = url;
            GameData.Instance.setRecordData("PersonData", personData);
        }
        if (target.floor) target.floor.enabled = false;
        if (target.canUse) target.node.children[0].active = true;
        target.node.setParent(target.handTarget);
        this.handTarget[num] = target.node;
        let pos = v2(-target.holdX, -target.holdY);
        pos = pos.rotate(toRadian(target.handAngle));
        target.node.setPosition(v3(pos.x, pos.y));
        target.rig.gravityScale = 0;
        target.rig.type = ERigidBody2DType.Animated;
        target.rig.enabledContactListener = false;
        target.collider.enabled = false;
        if (target.canBounce) this.HandState(HandState.Bounce, num);
        if (target.canLifting) this.HandState(HandState.Lifting, num);
    }

    HandOff(target: Node) {
        let num = this.handTarget.indexOf(target);
        if (num != -1) {
            let personData = GameData.Instance.getRecordData("PersonData");
            personData[this.id].hands[num] = "";
            GameData.Instance.setRecordData("PersonData", personData);
            this.handTarget[num] = null;
            // this.hands[num].angle = 0;
            target.setParent(MigaManager.Instance.game.children[0], true);
            Tween.stopAllByTarget(target);
            // this.HandState(HandState.None, num);
        }
    }

    Express(num: number) {
        if (this.expState == num) return;
        if (this.isEatDisgust) return;
        this.isExpress = num != 0;
        this.expState = num;
        for (let i = 0; i < this.expressions.children.length; i++) {
            const element = this.expressions.children[i];
            element.active = false;
        }
        for (let i = 0; i < this.effects.children.length; i++) {
            const element = this.effects.children[i];
            element.active = false;
        }
        this.eye.children[0].active = false;
        this.head.children[0].active = false;
        this.head.children[1].active = false;
        switch (this.expState) {
            case ExpressState.Heart:
                this.mouth.children[0].active = false;
                this.eye.active = false;
                this.eyebrow.active = true;
                this.effects.children[0].active = true;
                break;
            case ExpressState.Stun:
                this.effects.children[1].active = true;
            case ExpressState.Happy:
                this.mouth.children[0].active = false;
                this.eye.active = false;
                this.eyebrow.active = false;
                break;
            case ExpressState.Angry:
            case ExpressState.Disgust:
                this.head.children[num - 4].active = true;
            case ExpressState.Cry:
                this.mouth.children[0].active = false;
                this.eye.active = true;
                this.eyebrow.active = true;
                break;
            case ExpressState.Sleep:
                this.eye.children[0].active = true;
                this.effects.children[2].active = true;
                break;
            case ExpressState.None:
                this.mouth.children[0].active = true;
                this.eye.active = true;
                this.eyebrow.active = true;
                break;
        }
        if (num > 0) this.expressions.children[num - 1].active = true;
    }

    Mouth(num: number) {
        if (this.isExpress) return;
        if (this.isEatDisgust) return;
        if (this.mouthState == num) return;
        this.mouthState = num;
        switch (this.mouthState) {
            case MouthState.None:
                this.mouth.children[0].active = true;
                this.expressions.children[6].active = false;
                this.expressions.children[7].active = false;
                break;
            case MouthState.Open:
                this.mouth.children[0].active = false;
                this.expressions.children[6].active = true;
                this.expressions.children[7].active = false;
                break;
            case MouthState.Eat:
                this.mouth.children[0].active = false;
                this.expressions.children[6].active = false;
                this.expressions.children[7].active = true;
                this.expressions.children[7].children[0].getComponent(Animation).play();
                AudioManager.Instance.PlaySFX(this.clips[1]);
                this.eatNum++;
                break;
        }
    }

    EatEnd() {
        this.Mouth(0);
        if (this.eatNum > 3) {
            this.eatNum = 0;
            this.Express(ExpressState.Disgust);
            this.isEatDisgust = true;
            this.scheduleOnce(() => {
                this.isEatDisgust = false;
                this.Express(ExpressState.None);
            }, 2);
        }
    }

    Stand(num: number) {
        if (this.standState == num) return;
        this.standState = num;
        this.scheduleOnce(() => { this.node.setPosition(this.node.parent.children[0].getPosition()); });
        Tween.stopAllByTag(TweenTag.Stand, this.node);
        switch (this.standState) {
            case StandState.None:
                // this.eye.children[0].active = false;
                this.Express(ExpressState.None);
                tween(this.node).tag(TweenTag.Stand)
                    .to(0.2, { angle: 0 })
                    .start();
                break;
            case StandState.Sleep:
                // this.eye.children[0].active = true;
                this.Express(ExpressState.Sleep);
                tween(this.node).tag(TweenTag.Stand)
                    .to(0.2, { angle: 90 })
                    .start();
                break;
        }
    }

    HandState(state: number, num: number) {
        if (this.handStates[num] == state) return;
        if (state == HandState.None && this.handTarget[num]) return;
        this.handStates[num] = state;
        let angle = 0;
        let tag = num == 0 ? TweenTag.LeftArm : TweenTag.RightArm;
        Tween.stopAllByTag(tag, this.hands[num]);
        switch (this.handStates[num]) {
            case HandState.Catch:
                angle = num == 0 ? -50 : 50;
            case HandState.None:
                tween(this.hands[num]).tag(tag)
                    .to(0.2, { angle: angle })
                    .start();
                break;
            case HandState.Bounce:
                tween(this.hands[num]).tag(tag)
                    .to(0.2, { angle: num == 0 ? -50 : 50 })
                    .to(0.2, { angle: num == 0 ? -30 : 30 })
                    .union().repeatForever()
                    .start();
                let y = this.handTarget[num].getWorldPosition().y - this.node.children[26].getWorldPosition().y;
                tween(this.handTarget[num]).tag(tag)
                    .by(0.2, { position: v3(0, -y) })
                    .by(0.2, { position: v3(0, y) })
                    .union().repeatForever()
                    .start();
                break;
        }
    }

    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        let other = otherCollider.node;
        if (!this.isTouch && otherCollider.group == 1 << 2 || otherCollider.group == 1 << 8 || otherCollider.group == 1 << 10) {
            if (this.rig.gravityScale > 0 && other == this.rayTarget) {
                if (otherCollider.group == 1 << 10) {
                    this.rig.gravityScale = 0;
                    this.rig.linearVelocity = Vec2.ZERO;
                    this.node.setParent(other);
                    this.node.setPosition(other.children[0].getPosition());
                    this.Stand(1);
                    return;
                }
                if (other.getComponent(PolygonPlane)?.box) this.node.setParent(other.getComponent(PolygonPlane).box.node, true);
                else if (other.getComponent(LayerFloor)) this.layerFloor = other.getComponent(LayerFloor);
                else if (other.getComponent(PolygonPlane)?.floorBox) this.node.setParent(other.getComponent(PolygonPlane).floorBox.node, true);
                else this.node.setParent(MigaManager.Instance.game.children[0], true);
                this.rig.gravityScale = 0;
                this.rig.linearVelocity = Vec2.ZERO;
                let colliders = this.getComponentsInChildren(Collider2D);
                for (let i = 0; i < colliders.length; i++) {
                    const element = colliders[i];
                    if (element.tag == 1) element.enabled = true;
                }
                let ratio = clamp(Math.abs(this.touchUpPos.y - other.getPosition().y), 0, 2000) / 2000;
                // Tween.stopAllByTag(TweenTag.FallCollid, this.node);
                // tween(this.node).tag(TweenTag.FallCollid)
                //     .by(0.2, { position: v3(0, 100 * ratio) }, { easing: EasingType.sineOut })
                //     .by(0.2, { position: v3(0, -110 * ratio) }, { easing: EasingType.sineIn })
                //     .start();
            }
            else if (this.rig.gravityScale > 0) {
                if (otherCollider.group == 1 << 10) {
                    this.rig.gravityScale = 0;
                    this.rig.linearVelocity = Vec2.ZERO;
                    this.node.setParent(other);
                    this.node.setPosition(other.children[0].getPosition());
                    this.Stand(1);
                    return;
                }
                if (other.getComponent(PolygonPlane)?.box) this.node.setParent(other.getComponent(PolygonPlane).box.node, true);
                else if (other.getComponent(LayerFloor)) this.layerFloor = other.getComponent(LayerFloor);
                else if (other.getComponent(PolygonPlane)?.floorBox) this.node.setParent(other.getComponent(PolygonPlane).floorBox.node, true);
                else this.node.setParent(MigaManager.Instance.game.children[0], true);
                this.rig.gravityScale = 0;
                this.rig.linearVelocity = Vec2.ZERO;
                let colliders = this.getComponentsInChildren(Collider2D);
                for (let i = 0; i < colliders.length; i++) {
                    const element = colliders[i];
                    if (element.tag == 1) element.enabled = true;
                }
                Tween.stopAllByTag(TweenTag.FallCollid, this.node);
                let y = this.node.getWorldPosition().y - other.getWorldPosition().y - this.uiTransform.height / 2 * this.uiTransform.anchorY / 0.5;
                if (y < 0) {
                    tween(this.node).tag(TweenTag.FallCollid)
                        .by(0.2, { position: v3(0, -y) })
                        .start();
                }
            }
        }
        else if (otherCollider.group == 1 << 3) {
            if (this.isTouch) this.sitTarget = other;
        }
    }

    onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        let other = otherCollider.node;
        if (otherCollider.group == 1 << 3 && this.isTouch && other == this.sitTarget) {
            this.sitTarget = null;
        }
    }

}

enum PersonState {
    Idle,
    Touch,
    TouchLeft,
    TouchRight,
    TouchUp,
    TouchDown
}

enum ExpressState {
    None,
    Heart,
    Happy,
    Cry,
    Angry,
    Disgust,
    Stun,
    Sleep
}

enum MouthState {
    None,
    Open,
    Eat
}

enum StandState {
    None,
    Sleep
}

enum HandState {
    None,
    Catch,
    Bounce,
    Lifting
}